package com.hn658.base.service.common;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.common.extension.ExtensionLoader;
import com.alibaba.dubbo.common.logger.Logger;
import com.alibaba.dubbo.common.logger.LoggerFactory;
import com.alibaba.dubbo.common.utils.ClassHelper;
import com.alibaba.dubbo.common.utils.ConfigUtils;
import com.alibaba.dubbo.container.Container;
import com.alibaba.dubbo.container.Main;

/**
 * 应用启动类
 * 
 * @author davidcun
 * 
 */
public class Launcher {

	public static final String CONTAINER_KEY = "dubbo.container";

	public static final String SHUTDOWN_HOOK_KEY = "dubbo.shutdown.hook";
	
	public static final String INTERCEPTOR_CONFIG= "launcher.properties";

	private static final Logger logger = LoggerFactory.getLogger(Launcher.class);

	private static final ExtensionLoader<Container> loader = ExtensionLoader
			.getExtensionLoader(Container.class);

	private static volatile boolean running = true;
	
	private static List<LauncherInterceptor> lis = new ArrayList<LauncherInterceptor>();

	public static void main(String[] args) {
		
		loadInterceptors();
		
		beforeStartDubbo();
		
		startDubbo(args);
		
		afterStartDubbo();
		
		synchronized (LauncherInterceptor.class) {
			while (running) {
				try {
					Main.class.wait();
				} catch (Throwable e) {
				}
			}
		}
	}
	
	@SuppressWarnings("unchecked")
	private static void loadInterceptors(){
		
		List<java.net.URL> list = new ArrayList<java.net.URL>();
        try {
            Enumeration<java.net.URL> urls = ClassHelper.getClassLoader().getResources(INTERCEPTOR_CONFIG);
            list = new ArrayList<java.net.URL>();
            while (urls.hasMoreElements()) {
                list.add(urls.nextElement());
            }
        } catch (Throwable t) {
            logger.warn("Fail to load " + INTERCEPTOR_CONFIG + " file: " + t.getMessage(), t);
        }
        
        Set<String> itc = new HashSet<String>();
        for (java.net.URL url : list) {
        	InputStreamReader reader = null;
        	BufferedReader br = null;
			try{
				reader = new InputStreamReader(url.openStream());
				br = new BufferedReader(reader);
				String tmp = null;
				while((tmp=br.readLine()) != null){
					itc.add(tmp);
				}
				
			}catch(Exception e){
				e.printStackTrace();
				logger.error("load interceptor error", e);
			}finally{
				try {
					br.close();
				} catch (IOException e) {
					//ignore
				}
			}
		}
        for (String string : itc) {
			try {
				Class<LauncherInterceptor> cls = (Class<LauncherInterceptor>) ClassHelper.forName(string);
				lis.add(cls.newInstance());
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
				logger.error(String.format("can not found class %s",string), e);
			} catch (InstantiationException e) {
				e.printStackTrace();
				logger.error(String.format("instance class %s error",string), e);
			} catch (IllegalAccessException e) {
				e.printStackTrace();
				logger.error(String.format("instance class %s error",string), e);
			}
		}
		
	}
	
	private static void beforeStartDubbo(){
		
		for (LauncherInterceptor li : lis) {
			li.beforeStart();
		}
		
	}
	
	private static void afterStartDubbo(){
		for (LauncherInterceptor li : lis) {
			li.afterStart();
		}
		
	}
	
	private static void startDubbo(String[] args){
		try {
			if (args == null || args.length == 0) {
				String config = ConfigUtils.getProperty(CONTAINER_KEY,
						loader.getDefaultExtensionName());
				args = Constants.COMMA_SPLIT_PATTERN.split(config);
			}

			final List<Container> containers = new ArrayList<Container>();
			for (int i = 0; i < args.length; i++) {
				containers.add(loader.getExtension(args[i]));
			}
			logger.info("Use container type(" + Arrays.toString(args)
					+ ") to run dubbo serivce.");

			if ("true".equals(System.getProperty(SHUTDOWN_HOOK_KEY))) {
				Runtime.getRuntime().addShutdownHook(new Thread() {
					public void run() {
						for (Container container : containers) {
							try {
								container.stop();
								logger.info("Dubbo "
										+ container.getClass().getSimpleName()
										+ " stopped!");
							} catch (Throwable t) {
								logger.error(t.getMessage(), t);
							}
							synchronized (LauncherInterceptor.class) {
								running = false;
								LauncherInterceptor.class.notify();
							}
						}
					}
				});
			}

			for (Container container : containers) {
				container.start();
				logger.info("Dubbo " + container.getClass().getSimpleName()
						+ " started!");
			}
			System.out.println(new SimpleDateFormat("[yyyy-MM-dd HH:mm:ss]")
					.format(new Date()) + " Dubbo service server started!");
		} catch (RuntimeException e) {
			e.printStackTrace();
			logger.error(e.getMessage(), e);
			System.exit(1);
		}
	}
	
}
